Spring Boot:实现MyBatis动态创建表 您所在的位置:网站首页 mybatis 动态 表名 Spring Boot:实现MyBatis动态创建表

Spring Boot:实现MyBatis动态创建表

#Spring Boot:实现MyBatis动态创建表| 来源: 网络整理| 查看: 265

综合概述

在有些应用场景中,我们会有需要动态创建和操作表的需求。比如因为单表数据存储量太大而采取分表存储的情况,又或者是按日期生成日志表存储系统日志等等。这个时候就需要我们动态的生成和操作数据库表了。而我们都知道,以往我们使用MyBatis是需要提前生成包括Model,Mapper和XML映射文件的,显然因为动态生成和操作表的需求一开始表都是不存在的,所以也就不能直接通过MyBatis连接数据库来生成我们的数据访问层代码并用来访问数据库了。还好MyBatis提供了动态SQL,我们可以通过动态SQL,传入表名等信息然组装成建表和操作语句,接下来,我们就通过一个具体的案例来了解一下。

实现案例

先说一下我们要实现的案例,本案例中每个用户都会有一个自己日志表,其中的user_log_config表就是用户名和对应的日志表配置,每次往这个表添加配置的时候,系统就会根据配置信息给该用户生成一个日志存储表,表名是获取日志配置表里配置的表名称,并统一提供对这个日志表的操作接口。本教程案例基于 Spring Boot + Mybatis + MySQL 实现。

生成项目模板

为方便我们初始化项目,Spring Boot给我们提供一个项目模板生成网站。

1.  打开浏览器,访问:https://start.spring.io/

2.  根据页面提示,选择构建工具,开发语言,项目信息等。

3.  点击 Generate the project,生成项目模板,生成之后会将压缩包下载到本地。

4.  使用IDE导入项目,我这里使用Eclipse,通过导入Maven项目的方式导入。

创建数据库表

这里使用MySQL数据库,版本是8.0.16,在项目根目录下新建db目录,然后在其中编写一个数据库脚本文件。

在MySQL数据库新建一个springboot数据库,然后在此数据库中执行下面的脚本创建项目相关的表。

脚本文件

SQL脚本内容,注意,这里的user_log并不需要用到,事实上,user_log就是我们要生成的表结构,但为了一会儿MyBatis代码的生成,先创建一下,具体后续会讲到。

springboot.sql

-- ---------------------------- -- Table structure for user_log_config -- ---------------------------- DROP TABLE IF EXISTS `user_log_config`; CREATE TABLE `user_log_config` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', `name` varchar(50) NOT NULL COMMENT '用户名', `table_name` varchar(150) DEFAULT NULL COMMENT '用户对应的日志存储表', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8 COMMENT='用户日志表配置'; -- ---------------------------- -- Table structure for user_log -- ---------------------------- DROP TABLE IF EXISTS `user_log`; CREATE TABLE `user_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', `user_name` varchar(50) DEFAULT NULL COMMENT '用户名', `operation` varchar(50) DEFAULT NULL COMMENT '用户操作', `method` varchar(200) DEFAULT NULL COMMENT '请求方法', `params` varchar(5000) DEFAULT NULL COMMENT '请求参数', `time` bigint(20) NOT NULL COMMENT '执行时长(毫秒)', `ip` varchar(64) DEFAULT NULL COMMENT 'IP地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2897 DEFAULT CHARSET=utf8 COMMENT='用户操作日志'; 添加相关依赖

需要添加Spring Boot,Mybatis,MySQL,Swagger相关依赖。Swagger方便用来测试接口。

pom.xml

4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.5.RELEASE com.louis.springboot demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web io.springfox springfox-swagger2 2.9.2 io.springfox springfox-swagger-ui 2.9.2 org.mybatis.spring.boot mybatis-spring-boot-starter 2.0.0 mysql mysql-connector-java org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin src/main/java **/sqlmap/*.xml false src/main/resources **/*.* true 添加配置类

1. 添加swagger 配置

添加一个swagger 配置类,在工程下新建 config 包并添加一个 SwaggerConfig 配置类。

SwaggerConfig.java

package com.louis.springboot.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi(){ return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()).build(); } private ApiInfo apiInfo(){ return new ApiInfoBuilder() .title("SpringBoot API Doc") .description("This is a restful api document of Spring Boot.") .version("1.0") .build(); } }

2.添加MyBatis配置

添加MyBatis配置类,配置相关扫描路径,包括DAO,Model,XML映射文件的扫描。

在config包下新建一个MyBatis配置类,MybatisConfig.java。

MybatisConfig.java

package com.louis.springboot.demo.config; import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; @Configuration @MapperScan("com.louis.springboot.**.dao") // 扫描DAO public class MybatisConfig { @Autowired private DataSource dataSource; @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); sessionFactory.setTypeAliasesPackage("com.louis.springboot.**.model"); // 扫描Model PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sessionFactory.setMapperLocations(resolver.getResources("classpath*:**/sqlmap/*.xml")); // 扫描映射文件 return sessionFactory.getObject(); } }

3.添加数据源配置

将application.properties文件改名为application.yml ,并在其中添加MySQL数据源连接信息。

注意:

这里需要首先创建一个MySQL数据库,并输入自己的用户名和密码。这里的数据库是springboot。

另外,如果你使用的是MySQL 5.x及以前版本,驱动配置driverClassName是com.mysql.jdbc.Driver。

application.yml 

server: port: 8080 spring: datasource: driverClassName: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8 username: root password: 123456 生成MyBatis模块

由于手动编写MyBatis的Model、DAO、XML映射文件比较繁琐,通常都会通过一些生成工具来生成。MyBatis官方也提供了生成工具(MyBaits Generator),另外还有一些基于官方基础上改进的第三方工具,比如MyBatis Plus就是国内提供的一款非常优秀的开源工具,网上相关教程比较多,这里就不再赘述了。

这里提供一些资料作为参考。

Mybatis Generator 官网:http://www.mybatis.org/generator/index.html

Mybatis Generator 教程:https://blog.csdn.net/testcs_dn/article/details/77881776

MyBatis Plus 官网: http://mp.baomidou.com/#/

MyBatis Plus 官网: http://mp.baomidou.com/#/quick-start

代码生成好之后,分別将MODEL、DAO、XML映射文件拷贝到相应的包里。

生成的Model,如下是user_log_config表对应的Model对象UserLogConfig。

UserLogConfig.java

package com.louis.springboot.demo.model; public class UserLogConfig { private Long id; private String name; private String tableName; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name == null ? null : name.trim(); } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName == null ? null : tableName.trim(); } }

打开Mapper,我们看到MyBatis Generator给我们默认生成了一些增删改查的方法,另外添加一个查询全部的方法。

UserLogConfigMapper.java

package com.louis.springboot.demo.dao; import java.util.List; import com.louis.springboot.demo.model.UserLogConfig; public interface UserLogConfigMapper { int deleteByPrimaryKey(Long id); int insert(UserLogConfig record); int insertSelective(UserLogConfig record); UserLogConfig selectByPrimaryKey(Long id); int updateByPrimaryKeySelective(UserLogConfig record); int updateByPrimaryKey(UserLogConfig record); public List selectAll(); }

在UserLogConfigMapper.xml中编写selectAll的SQL语句。

UserLogConfigMapper.xml

id, name, table_name select from user_log_config where id = #{id,jdbcType=BIGINT} delete from user_log_config where id = #{id,jdbcType=BIGINT} insert into user_log_config (id, name, table_name ) values (#{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{tableName,jdbcType=VARCHAR} ) insert into user_log_config id, name, table_name, #{id,jdbcType=BIGINT}, #{name,jdbcType=VARCHAR}, #{tableName,jdbcType=VARCHAR}, update user_log_config name = #{name,jdbcType=VARCHAR}, table_name = #{tableName,jdbcType=VARCHAR}, where id = #{id,jdbcType=BIGINT} update user_log_config set name = #{name,jdbcType=VARCHAR}, table_name = #{tableName,jdbcType=VARCHAR} where id = #{id,jdbcType=BIGINT} select from user_log_config

编写UserLogConfig的服务接口。

UserLogConfigService.java

package com.louis.springboot.demo.service; import java.util.List; import com.louis.springboot.demo.model.UserLogConfig; public interface UserLogConfigService { /** * 保存用户日志配置 * @return */ void save(UserLogConfig userLogConfig); /** * 查找全部用户日志配置 * @return */ List findAll(); }

编写UserLogConfig的服务实现类。

UserLogConfigServiceImpl.java

package com.louis.springboot.demo.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.louis.springboot.demo.dao.UserLogConfigMapper; import com.louis.springboot.demo.model.UserLogConfig; import com.louis.springboot.demo.service.UserLogConfigService; @Service public class UserLogConfigServiceImpl implements UserLogConfigService { @Autowired private UserLogConfigMapper userLogConfigMapper; @Override public void save(UserLogConfig userLogConfig) { if(userLogConfig.getId() != null && !"".equals(userLogConfig.getId())) { // 更新 userLogConfigMapper.updateByPrimaryKeySelective(userLogConfig); } else { // 插入 userLogConfigMapper.insertSelective(userLogConfig); } } @Override public List findAll() { return userLogConfigMapper.selectAll(); } }

编写UserLogConfig的控制器。

UserLogConfigController.java

package com.louis.springboot.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.louis.springboot.demo.model.UserLogConfig; import com.louis.springboot.demo.service.UserLogConfigService; @RestController @RequestMapping("user/log/config") public class UserLogConfigController { @Autowired private UserLogConfigService userLogConfigService; @PostMapping(value="/save") public Object save(@RequestBody UserLogConfig userLogConfig) { userLogConfigService.save(userLogConfig); return 1; } @GetMapping(value="/findAll") public Object findAll() { return userLogConfigService.findAll(); } }

现在我们来讲解如何动态实现动态生成用户日志存储表(user_log的表结构),之前我们通过MyBatis生成了user_log的服务访问层代码,下面是Model类UserLog,你可以直接用或改个名称都行,我们这里就不改了。

UserLog.java

package com.louis.springboot.demo.model; public class UserLog { private Long id; private String userName; private String operation; private String method; private String params; private Long time; private String ip; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName == null ? null : userName.trim(); } public String getOperation() { return operation; } public void setOperation(String operation) { this.operation = operation == null ? null : operation.trim(); } public String getMethod() { return method; } public void setMethod(String method) { this.method = method == null ? null : method.trim(); } public String getParams() { return params; } public void setParams(String params) { this.params = params == null ? null : params.trim(); } public Long getTime() { return time; } public void setTime(Long time) { this.time = time; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip == null ? null : ip.trim(); } }

修改UserLogMapper,将原有的接口都加上tableName参数,传入表名以确定要操作的表。另外额外添加了三个跟建表有关的方法。

UserLogMapper.java

package com.louis.springboot.demo.dao; import java.util.List; import org.apache.ibatis.annotations.Param; import com.louis.springboot.demo.model.UserLog; public interface UserLogMapper { int deleteByPrimaryKey(@Param("tableName")String tableName, @Param("id")Long id); int insert(@Param("tableName")String tableName, @Param("userLog") UserLog userLog); int insertSelective(@Param("tableName")String tableName, @Param("userLog") UserLog record); UserLog selectByPrimaryKey(@Param("tableName")String tableName, @Param("id")Long id); int updateByPrimaryKeySelective(@Param("tableName")String tableName, @Param("userLog") UserLog record); int updateByPrimaryKey(@Param("tableName")String tableName, @Param("userLog") UserLog record); /** * 查找全部 * @param tableName * @return */ List selectAll(@Param("tableName")String tableName); /** * 是否存在表 * @param tableName * @return */ int existTable(@Param("tableName")String tableName); /** * 删除表 * @param tableName * @return */ int dropTable(@Param("tableName")String tableName); /** * 创建表 * @param tableName * @return */ int createTable(@Param("tableName")String tableName); }

修改UserLogMapper.xml,将原来用表名user_log的地方替换成${tableName},表示表名由外部方法传入。另外编写另外三个建表相关的语句,检查表是否存在和删除表的语句比较简单,创建表的只要把建表语句拷贝过来,然后把表名替换成${tableName}就行了。

UserLogMapper.xml

id, user_name, operation, method, params, time, ip select from ${tableName} where id = #{id,jdbcType=BIGINT} delete from ${tableName} where id = #{id,jdbcType=BIGINT} insert into ${tableName} (id, user_name, operation, method, params, time, ip) values (#{id,jdbcType=BIGINT}, #{userName,jdbcType=VARCHAR}, #{operation,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR}, #{params,jdbcType=VARCHAR}, #{time,jdbcType=BIGINT}, #{ip,jdbcType=VARCHAR}) insert into ${tableName} id, user_name, operation, method, params, time, ip, #{id,jdbcType=BIGINT}, #{userName,jdbcType=VARCHAR}, #{operation,jdbcType=VARCHAR}, #{method,jdbcType=VARCHAR}, #{params,jdbcType=VARCHAR}, #{time,jdbcType=BIGINT}, #{ip,jdbcType=VARCHAR}, update ${tableName} user_name = #{userName,jdbcType=VARCHAR}, operation = #{operation,jdbcType=VARCHAR}, method = #{method,jdbcType=VARCHAR}, params = #{params,jdbcType=VARCHAR}, time = #{time,jdbcType=BIGINT}, ip = #{ip,jdbcType=VARCHAR}, where id = #{id,jdbcType=BIGINT} update ${tableName} set user_name = #{userName,jdbcType=VARCHAR}, operation = #{operation,jdbcType=VARCHAR}, method = #{method,jdbcType=VARCHAR}, params = #{params,jdbcType=VARCHAR}, time = #{time,jdbcType=BIGINT}, ip = #{ip,jdbcType=VARCHAR} where id = #{id,jdbcType=BIGINT} select from ${tableName} select count(*) from information_schema.TABLES where table_name=#{tableName} DROP TABLE IF EXISTS ${tableName} CREATE TABLE ${tableName} ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号', `user_name` varchar(50) DEFAULT NULL COMMENT '用户名', `operation` varchar(50) DEFAULT NULL COMMENT '用户操作', `method` varchar(200) DEFAULT NULL COMMENT '请求方法', `params` varchar(5000) DEFAULT NULL COMMENT '请求参数', `time` bigint(20) NOT NULL COMMENT '执行时长(毫秒)', `ip` varchar(64) DEFAULT NULL COMMENT 'IP地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2897 DEFAULT CHARSET=utf8 COMMENT='用户操作日志';

编写用户日志的服务接口,包含一个保存方法和一个查询方法。

UserLogService.java

package com.louis.springboot.demo.service; import java.util.List; import com.louis.springboot.demo.model.UserLog; public interface UserLogService { /** * 保存用户日志 * @return */ void save(String tableName, UserLog userLog); /** * 查找全部用户日志 * @return */ List findAll(String tableName); }

编写用户日志的服务实现类,包含保存方法和查询方法的实现。

UserLogServiceImpl.java

package com.louis.springboot.demo.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.louis.springboot.demo.dao.UserLogMapper; import com.louis.springboot.demo.model.UserLog; import com.louis.springboot.demo.service.UserLogService; @Service public class UserLogServiceImpl implements UserLogService { @Autowired private UserLogMapper userLogMapper; @Override public void save(String tableName, UserLog userLog) { // 插入 userLogMapper.insertSelective(tableName, userLog); } @Override public List findAll(String tableName) { return userLogMapper.selectAll(tableName); } }

为了接口传表名方便,我们这里在UserLog类里加入一个tableName属性,用来给接口传入表名。

UserLog.java

package com.louis.springboot.demo.model; public class UserLog { private Long id; private String userName; private String operation; private String method; private String params; private Long time; private String ip; private String tableName; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName == null ? null : userName.trim(); } public String getOperation() { return operation; } public void setOperation(String operation) { this.operation = operation == null ? null : operation.trim(); } public String getMethod() { return method; } public void setMethod(String method) { this.method = method == null ? null : method.trim(); } public String getParams() { return params; } public void setParams(String params) { this.params = params == null ? null : params.trim(); } public Long getTime() { return time; } public void setTime(Long time) { this.time = time; } public String getIp() { return ip; } public void setIp(String ip) { this.ip = ip == null ? null : ip.trim(); } public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } }

编写服务控制器UserLogController并调用服务的相关接口。

UserLogController.java

package com.louis.springboot.demo.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.louis.springboot.demo.model.UserLog; import com.louis.springboot.demo.service.UserLogService; @RestController @RequestMapping("user/log") public class UserLogController { @Autowired private UserLogService userLogService; @PostMapping(value="/save") public Object save(@RequestBody UserLog userLog) { String tableName = userLog.getTableName(); userLogService.save(tableName, userLog); return 1; } @GetMapping(value="/findAll") public Object findAll(String tableName) { return userLogService.findAll(tableName); } }

修改UserLogConfigServiceImpl的save方法,实现在添加配置的时候生成对应的表。

UserLogConfigServiceImpl.java

package com.louis.springboot.demo.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.louis.springboot.demo.dao.UserLogConfigMapper; import com.louis.springboot.demo.dao.UserLogMapper; import com.louis.springboot.demo.model.UserLogConfig; import com.louis.springboot.demo.service.UserLogConfigService; @Service public class UserLogConfigServiceImpl implements UserLogConfigService { @Autowired private UserLogConfigMapper userLogConfigMapper; @Autowired private UserLogMapper userLogMapper; @Override public void save(UserLogConfig userLogConfig) { // 插入 userLogConfigMapper.insertSelective(userLogConfig); // 添加配置时,创建日志存储表 String tableName = userLogConfig.getTableName(); if(userLogMapper.existTable(tableName) > 0) { userLogMapper.dropTable(tableName); } userLogMapper.createTable(tableName); } @Override public List findAll() { return userLogConfigMapper.selectAll(); } }

 

编译测试运行

1.  右键项目 -> Run as -> Maven install,开始执行Maven构建,第一次会下载Maven依赖,可能需要点时间,如果出现如下信息,就说明项目编译打包成功了。

2.  右键文件 DemoApplication.java -> Run as -> Java Application,开始启动应用,当出现如下信息的时候,就说明应用启动成功了,默认启动端口是8080。

3.  打开浏览器,访问:http://localhost:8080/swagger-ui.html,进入swagger接口文档界面。

4.  测试UserLogConfigMapper的save保存接口,输入以下参数进行测试。

{ "id": 1, "name": "xiaoming", "tableName": "xiaoming" }

成功之后调UserLogConfigMapper的findAll接口,可以看到配置信息已经成功插入。

并且我们可以通过MySQL客户端查看到,在配置生成的同时生成了一个表名为xiaoming的数据库表。

5.  测试UserLogController的save保存接口,输入以下参数进行测试。

{ "id": 1, "ip": "139.123.123.100", "method": "save", "operation": "save", "params": "string name", "tableName": "xiaoming", "time": 0, "userName": "xiaoming" }

成功之后调UserLogController的findAll接口,可以看到配置信息已经成功插入。

测试到此,我们成功的保存了配置信息,并且动态创建了一个表,然后成功的往表里插入了一点数据,并通过接口查询出了插入的数据。

 

参考资料

MyBatis 官网:http://www.mybatis.org/mybatis-3/zh/index.html

MyBatis Generator 官网:http://www.mybatis.org/generator/index.html

MyBatis Plus 官网: http://mp.baomidou.com/#/quick-start

相关导航

Spring Boot 系列教程目录导航

Spring Boot:快速入门教程

Spring Boot:整合Swagger文档

Spring Boot:整合MyBatis框架

Spring Boot:实现MyBatis分页

源码下载

码云:https://gitee.com/liuge1988/spring-boot-demo.git

作者:朝雨忆轻尘出处:https://www.cnblogs.com/xifengxiaoma/ 版权所有,欢迎转载,转载请注明原文作者及出处。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有